<template>
  <div id="app">
    <el-container class="main-container">
      <el-header class="header">
        <h2>Redis以及RabbitMQ演示</h2>
      </el-header>
      <el-main>
        <el-row :gutter="20">
          <el-col :span="8">
            <div class="grid-content bg-purple">
              <p>redis获取数据(解决缓存穿透问题)</p>
              <div class="redis-search">
                <div><el-input v-model.trim="redis.search" placeholder="查询用户名(张三, 李四, 王五)"></el-input></div>
                <div><el-button type="primary" @click="redisSearch">查询</el-button></div>
              </div>
              <div class="info-list" ref="list1">
                <ul v-for="(item, index) in redis.list"  :key='index'>
                  <li><i>{{ item.time }}</i>查询用户名：{{ item.name }}</li>
                  <li v-if="item.source === 'database'"><i>{{ item.time }}</i>从数据库中读取到数据：{{ item.name }}, 账号{{item.data.account}}</li>
                  <li v-if="item.source === 'redis'"><i>{{ item.time }}</i>从redis中读取到数据：{{ item.data.name ? item.data.name: '[空]' }}, 账号{{item.data.account ? item.data.account: '[空]'}}</li>
                  <li v-if="item.source === 'redis'"><i>{{ item.time }}</i>30秒后失效，查询将重置ttl</li>
                  <li v-if="item.source === 'none'"><i>{{ item.time }}</i>未查询到数据,已将redis中数据置为空值</li>
                </ul>
              </div>
            </div>
          </el-col>
          <el-col :span="8">
            <div class="grid-content bg-purple">
              <p>redis分布式锁演示(带watchdog)</p>
              <div class="redis-search">
                <div>
                  <p>点击按钮创建分布式锁</p>
                </div>
                <div><el-button type="primary" @click="createdistributedLock">创建</el-button></div>
              </div>
              <div class="info-list" ref="list2">
                <ul v-for="(item, index) in lock.list"  :key='index'>
                  <li :class="item.color" ><i>{{ item.time }}</i>{{ item.msg }}</li>
                </ul>
              </div>
            </div>
          </el-col>
          <el-col :span="8">
            <div class="grid-content bg-purple">
              <p>redis+rabbitmq(分布式锁+topic队列+延迟队列)</p>
              <div class="redis-search">
                <div>
                  <p>点击生产消息</p>
                </div>
                <div><el-button type="primary" @click="createRabbitMQMessage">生产</el-button></div>
              </div>
              <div class="info-list" ref="list3">
                <ul v-for="(item, index) in rabbitmq.list"  :key='index'>
                  <li :class="item.color" ><i>{{ item.time }}</i>{{ item.msg }}</li>
                </ul>
              </div>
            </div>
          </el-col>
        </el-row>
      </el-main>
    </el-container>
  </div>
</template>

<script>
import { Message } from 'element-ui'
import request from '@/utils/request'

export default {
  name: 'RedisRabbitMQ',
  mounted () {
    // 连接一下websocket服务器 用来接收异步的消息
    this.connectWs()
  },
  data () {
    return {
      ws: null,
      redis: {
        search: '',
        list: []
      },
      lock: {
        list: [],
        locked: false
      },
      rabbitmq: {
        list: [],
        locked: false
      }
    }
  },
  methods: {
    // 用户查询方法
    async redisSearch () {
      // 验证一下空或者非中文
      if (this.redis.search === '') {
        Message.error({
          message: '请输入查询的用户名',
          duraton: 2000,
          showClose: true
        })
        return
      }
      if (/^[\u4e00-\u9fa5]+$/.test(this.redis.search) === false) {
        Message.error({
          message: '请输入中文用户名',
          duraton: 2000,
          showClose: true
        })
        return
      }
      const data = {
        name: this.redis.search
      }
      const res = await request.post('redis/getFirstUserInfoByName', data)
      if (res.code === 200) {
        this.redis.list.push(res.data)
        this.changeList1Height()
      } else {
        Message.error({
          message: '错误',
          duraton: 2000,
          showClose: true
        })
      }
    },
    // 获取系统时间方法
    async getSysDate () {
      const res = await request.post('utils/getSysDate')
      if (res.code !== 200) {
        Message.error({
          message: '获取系统时间失败',
          duraton: 1000,
          showClose: true
        })
        return ''
      } else {
        return res.data.date
      }
    },
    // 分布式锁创建方法
    async createdistributedLock () {
      // 未锁定状态才进行提示
      if (!this.lock.locked) {
        this.lock.locked = true
        const nowDate = await this.getSysDate()
        const nowHms = nowDate ? nowDate.split(' ')[1] : nowDate
        this.createLockListData('normal', '创建redis分布式锁,程序将执行15秒', nowHms)
        this.createLockListData('normal', 'watchdog将每10秒重置一次锁', nowHms)
      }
      // 发送请求并且不增加loading
      request.post('redis/distributedLock', { request_not_loading: true }).then((res) => {
        // 如果返回值出错的话就执行这个
        if (res.code !== 200) {
          this.createLockListData('error', res.message, res.data.time)
          return
        }
        // 返回值成功 说明锁已经执行完成了
        // 返回了结果解除锁定状态
        this.lock.locked = false
        this.createLockListData('tip', '业务执行完成,分布式锁已删除', res.data.time)
      })
    },
    // 生成分布式锁消息栏的消息 type error/normal/tip
    createLockListData (type, msg, time, list = 'lock') {
      let colorClass = ''
      switch (type) {
        case 'error':
          colorClass = 'color-red'
          break
        case 'tip':
          colorClass = 'color-blue'
          break
        default:
          colorClass = ''
          break
      }
      const listData = {
        color: colorClass,
        msg: msg,
        time: time
      }
      if (list === 'lock') {
        this.lock.list.push(listData)
        this.changeList2Height()
      } else {
        this.rabbitmq.list.push(listData)
        this.changeList3Height()
      }
    },
    // rabbitmq演示方法
    async createRabbitMQMessage () {
      // 未锁定状态才进行提示
      if (!this.rabbitmq.locked) {
        this.rabbitmq.locked = true
        const nowDate = await this.getSysDate()
        const nowHms = nowDate ? nowDate.split(' ')[1] : nowDate
        this.createLockListData('normal', '向rabbitmq, topic队列中发送消息', nowHms, 'rabbitmq')
        this.createLockListData('normal', '消费完成后会再发送延迟消息', nowHms, 'rabbitmq')
        this.createLockListData('tip', '向topic队列发送消息', nowHms, 'rabbitmq')
      }
      // 发送请求并且不增加loading
      request.post('redis/distributedLockAndRabbitMQ', { request_not_loading: true }).then((res) => {
        // 如果返回值出错的话就执行这个
        if (res.code !== 200) {
          this.createLockListData('error', res.message, res.data.time, 'rabbitmq')
          return
        }
        // 返回值成功 说明锁已经执行完成了
        // 返回了结果解除锁定状态
        this.rabbitmq.locked = false
        // this.createLockListData('tip', '已向topic队列发送消息', res.data.time, 'rabbitmq')
      })
    },
    // 静默连接websocket
    connectWs () {
      this.ws = new WebSocket('ws://' + process.env.VUE_APP_WEBSOCKET_URL + '/?type=redis_demo&token=' + this.$store.state.user.userInfo.token)
      this.ws.onerror = (event) => {
        Message.error({
          message: '连接websocet服务器失败',
          duraton: 1000,
          showClose: true
        })
        this.ws = null
      }
      this.ws.onmessage = (event) => {
        // this.dealWsMessage(event.data)
        this.dealWsMessage(event.data)
      }
      // this.ws.onclose = (event) => {
      //   Message.error({
      //     message: 'websocket连接已断开',
      //     duraton: 1000,
      //     showClose: true
      //   })
      //   this.ws = null
      // }
    },
    dealWsMessage (data) {
      data = JSON.parse(data)
      if (data.mode && data.mode === 'heart') return
      // 不同类型进行处理 ['redis-demo'];
      const res = data.data
      if (data.type) {
        switch (data.type) {
          case 'redis-demo':
            // 普通消息直接显示
            this.createLockListData('tip', res.message, res.date.split(' ')[1])
            break
          case 'rabbitmq-demo':
            // 消息显示
            this.createLockListData('tip', res.message, res.date.split(' ')[1], 'rabbitmq')
            break
          default:
            break
        }
      }
    },
    // 变更list栏目的滚动条
    changeList1Height () {
      this.$nextTick(() => {
        this.$refs.list1.scrollTop = this.$refs.list1.scrollHeight
      })
    },
    changeList2Height () {
      this.$nextTick(() => {
        this.$refs.list2.scrollTop = this.$refs.list2.scrollHeight
      })
    },
    changeList3Height () {
      this.$nextTick(() => {
        this.$refs.list3.scrollTop = this.$refs.list3.scrollHeight
      })
    }
  }
}
</script>
<style lang="less" scoped>
  .main-container {
    padding: 30px;

    .header {
      text-align: center;
    }

    .grid-content {
      border-right: 1px solid #eee;
      height: calc(100vh - 220px);
      min-height: 580px;

      p {
        text-align: center;
      }
    }

    .redis-search {
      padding: 20px 10px;
      display: flex;

      div:first-child {
        flex: 1;
        margin-right: 10px;

        p {
          line-height: 40px;
          text-align: center;
        }
      }
    }

    .info-list {
      height: calc(100vh - 300px);
      min-height: 300px;
      overflow: auto;

      ul {

        li {
          margin-bottom: 10px;
          font-size: 14px;

          i {
            margin-right: 10px;
            color: #979797;
          }
        }

        .color-red {
          color: rgb(217, 46, 36);
        }

        .color-blue {
          color: #409EFF;
        }
      }
    }
  }
</style>
